package edu.intprog.egreeting;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Projections;

import edu.intprog.egreeting.basic.EgreetingBaseServlet;
import edu.intprog.egreeting.beans.GreetingHistory;
import edu.intprog.egreeting.beans.UserDef;
import edu.intprog.sql.SessionManager;

/**
 * Servlet implementation class for Servlet: StatsCacheServlet
 *
 */
public class StatsCacheServlet extends EgreetingBaseServlet implements javax.servlet.Servlet,Runnable {
	static final long serialVersionUID = 1L;

	static final int REFRESH_RATE = 5; //refresh rate in minutes
	private boolean running = true;
	private long lastModified = -1;
	private Integer currentNumOfUsers = 0;
	private Integer currentNumOfSentGreetings = 0;

	/* (non-Java-doc)
	 * @see javax.servlet.http.HttpServlet#HttpServlet()
	 */
	public StatsCacheServlet() {
		super();
		
		//run the monitor thread which will update the values every REFRESH_RATE minutes only if values differ
		Thread monitor = new Thread(this);
		monitor.start();
	}   	

	@Override
	public void service(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException 
	{
		if( "GET".equals( request.getMethod() ) )  
		{
			//only preform 
			long lastModified  = -1;
			
			while ((lastModified = getLastModified(request))==-1) 
			{
				//loop will be entered only the first time the servlet runs
				//this was added so that the thread which was started in the c'tor
				//will update the last modified time correctly
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					//thats OK
				}
			}
			
			//check the browser version of the page
			long ifModSince = request.getDateHeader( "If-Modified-Since" );
			if( ifModSince < lastModified ) 
			{
				//update needed
				doGet( request, response );
			}
			else
			{
				//no update needed
				response.setStatus( HttpServletResponse.SC_NOT_MODIFIED );
			}
		}
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//add the number of registered users and the number of sent requests to the request 
		request.setAttribute("registeredUsers", currentNumOfUsers.toString());
		request.setAttribute("sentGreetings", currentNumOfSentGreetings.toString());
		getServletContext().getRequestDispatcher("/eGreetingStats.jsp").forward(request, response);
	}

	@Override
	public long getLastModified(HttpServletRequest request)
	{
		//return the last update time of the page
		return lastModified;
	}

	@Override
	public void destroy() {
		//stop running the thread
		running = false;
		super.destroy();
	}

	@Override
	public void run() {
		// this thread will update the values every REFRESH_RATE minutes and only if values differ
		
		//get the latest values from the DB
		Transaction tx = null;
		while (running)
		{
			Integer numOfKnownUsers = currentNumOfUsers;
			Integer numSentGreetings = currentNumOfSentGreetings;
			try {
				Session session = SessionManager.getCurrentSession();
				tx = session.beginTransaction();
				Criteria crit = session.createCriteria(UserDef.class);
				crit.setProjection(Projections.rowCount());
				numOfKnownUsers = (Integer) crit.list().get(0);
				tx.commit();

				session = SessionManager.getCurrentSession();
				tx = session.beginTransaction();
				crit = session.createCriteria(GreetingHistory.class);
				crit.setProjection(Projections.rowCount());
				numSentGreetings = (Integer) crit.list().get(0);
				tx.commit();
			} catch (Exception e) {
				//should be ok - retry will occur in REFRESH_RATE minutes
			}

			//compare results to previous results
			if (numOfKnownUsers!=currentNumOfUsers || numSentGreetings!=currentNumOfSentGreetings)
			{
				//results differ - update is required
				currentNumOfUsers = numOfKnownUsers;
				currentNumOfSentGreetings = numSentGreetings;
				lastModified = System.currentTimeMillis() / 1000 * 1000;
			}

			try {
				Thread.sleep(REFRESH_RATE*60*1000); //5 minutes refresh rate
			} catch (InterruptedException e) {
				//should be ok - running will be set to false by the destroy
			}
		}

	}
}